/*
	Compresor Gzip
    Copyright (C) 2012 Darío López Padial 
    @bukosabino

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

/**
 @file vectorbits.cpp
 @brief Implementación de la Clase Vector Dinámico de bits
 @author Dario Lopez Padial
 */

#include <iostream>
#include <cassert>
#include "vectorbits.h"

using namespace std;

VB :: VB (unsigned long n, int m) {
	_num_bits = 0;
	for (int i = 0; i<m; i++) {
		if (n % 2)
			(* this) += true;
		else
			(* this) += false;
		n = n/2;
	}
	Invertir ();
}

void VB :: operator += ( unsigned char byte ) {
	VB auxiliar;
	for ( int i=0; i<8; i++ ) {
		if ( ( ( byte >> i ) % 2 ) == 0 ) {
			auxiliar += false; 
		}
		else {
			auxiliar += true;
		}
	}
	( * this ) += auxiliar;
}

void VB :: Invertir ( ) {
	bool aux;
	for ( int i = 0; i < ( Size() / 2 ); i++ ) {
		aux = ( * this ) [i];
		Set(i, (* this) [  (Size() - i) - 1  ] );
		Set( (Size () -i) -1, aux );
	}
}

void VB :: Escribir ( std::ostream & os ) {
	for ( unsigned int i=0; i< _num_bits/8 ; i++ ) {
		os.put( _vector_char.Get (i) );
	}
}

bool VB :: operator [] ( unsigned int posicion ) const {
	assert ( posicion <= _num_bits );
	unsigned int h = static_cast < unsigned int > ( posicion / 8 );
	unsigned char bloque =  _vector_char.Get( h );
	return ( bloque & static_cast < unsigned char > ( 1 << ( posicion % 8 ) ) );
}

void VB :: Set ( int posicion, bool dato ) {
	if ( ( * this ) [posicion] != dato ) {
		char bloque;
		bloque = _vector_char.Get ( posicion / 8 );
		bloque = static_cast < char > ( bloque ^ ( 1 << ( posicion % 8 ) ) );
		_vector_char.Set ( posicion / 8, bloque );
	}
}

void VB :: operator += ( bool dato ) { 
	if ( _num_bits == ( _vector_char.Size() * 8 ) ) {
		Resize ( _num_bits * 3 );
		Set ( _num_bits, dato );
		_num_bits += 1;
	}
	else {
		Set ( _num_bits, dato );
		_num_bits += 1;
	}
}

void VB :: operator += ( VB & vector_aux ) {
	for ( int i = 0; i < vector_aux.Size (); i++ ) {
		( * this ) += vector_aux [i];
	}
}

bool VB :: operator == ( VB & vector_aux ) {
	bool iguales = true;
	if ( vector_aux.Size ( ) == Size ( ) ) {
		for ( int i=0; ( i<Size ( ) ) && ( iguales == true ); i++ ) {
			if ( vector_aux [i] != ( * this ) [i] ) {
				iguales = false;
			}
		}	
	}
	else {
		iguales = false;
	}
	return iguales;
}

bool VB :: operator != ( VB & vector_aux ) {
	return !( ( * this ) == vector_aux );
}

VB & VB :: operator = ( const VB & vector_aux ) {
	_num_bits = vector_aux._num_bits;
	_vector_char = vector_aux._vector_char;
	return ( * this );
}

void VB::Resize( int n ) {
	int tam=n/8 + 1;
	_vector_char.Resize ( tam );
}

ostream & operator << ( ostream & os, const VB & vector_aux ) {
	for ( int i = 0; i < vector_aux.Size ( ); i++ ) {
		if (vector_aux [i] == 0)
			os << "0";
		else
			os << "1";
		if ( ( i+1 ) % 8 == 0)
			os << " ";
	}
	return os;
}

istream & operator >> ( istream & is, VB & vector_aux ) {
	char c;
	while ( isspace ( is.peek ( ) ) ) {
		is.get( c );
	}
	while ( is.peek ( ) == '0' || is.peek ( ) == '1' ) {
		cin.get ( c );
		if ( c == '1' ) {
			vector_aux += true;
		}
		if (c == '0' ) {
			vector_aux += false;
		}
	}
	return is;
}
